package patterns.statePattern;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

public class TrafficLights {
	private String address;
	protected State state;
	protected Map<State, Integer>[] stateTimeMapper;
	private ConcurrentLinkedQueue<Walkman> walkmanQueue = new ConcurrentLinkedQueue<>();
	private ConcurrentLinkedQueue<Vehicle> vehicleQueue = new ConcurrentLinkedQueue<>();
	private boolean walkmanPassing = false;
	private boolean vehiclePassing = false;
	WalkmanAndVehiclePassingThread noticeThread = new WalkmanAndVehiclePassingThread(this);
	Map<String, State> walkmanPassingState;
	private ConcurrentLinkedQueue<Walkman> walkmanPassingAdd = new ConcurrentLinkedQueue<>();
	private ConcurrentHashMap<Walkman, Integer> walkmanPassingDelete = new ConcurrentHashMap<>();
	private ConcurrentLinkedQueue<Vehicle> vehiclePassingAdd = new ConcurrentLinkedQueue<>();

	private TrafficLights(String address, State beginState, Map<State, Integer>[] stateTimeMapper,
			Map<String, State> walkmanPassingState) {
		// TODO Auto-generated constructor stub
		this.address = address;
		this.stateTimeMapper = stateTimeMapper;
		this.state = beginState;
		this.walkmanPassingState = walkmanPassingState;
		stateSetter();
	}

	public TrafficMessage vehicleGo() {
		TrafficMessage trafficMessage = state.vehicleGo();
		trafficMessage.setMessage("you are driving a vehicle and at " + address + "\n" + trafficMessage.getMessage());
		return trafficMessage;
	}

	public TrafficMessage walkManGo() {
		TrafficMessage trafficMessage = state.walkmanGo();
		trafficMessage.setMessage("you are a walk-man and at " + address + "\n" + trafficMessage.getMessage());
		return trafficMessage;
	}

	public State getState() {
		return this.state;
	}

	public void setState(State state) {
		System.out.println("====start set state:" + state.getColor());
		boolean tempPassingState = walkmanPassing;// 建立临时变量是防止在这里更改原队列和等待队列的元素造成的正在运行的线程错误
		if (noticeThread.isAlive()) {
			noticeThread.setOverTime(true);
			walkmanPassing = false;// 防止调度线程卡死或者延迟导致行人通过状态更新不及时
		}
		while (true) {
			if (!noticeThread.isAlive()) {
				break;
			}
		}
		if (tempPassingState == true) {
			walkmanQueue.addAll(walkmanPassingAdd);// 将上次行人通过中加入的元素中剩下的元素加到原始队列中
			walkmanPassingAdd.removeAll(walkmanPassingAdd);
		} else if (state.getClass().getSimpleName().equals(YellowLight.class.getSimpleName())) {
			vehicleQueue.addAll(vehiclePassingAdd);
			vehiclePassingAdd.removeAll(vehiclePassingAdd);
		}
		this.state = state;
		System.out.println("====end set state:" + state.getColor());
		noticeThread = new WalkmanAndVehiclePassingThread(this);
		noticeThread.start();
	}

	@SuppressWarnings("unchecked")
	protected void stateSetter() {
		Map<State, Integer>[] assembledTimes = new Map[stateTimeMapper.length];
		String beginStateName = state.getClass().getSimpleName();
		int beginIndex = 0;
		boolean find = false;
		for (int i = 0; i < stateTimeMapper.length; i++) {
			State state = stateTimeMapper[i].keySet().iterator().next();
			if (beginStateName.equals(state.getClass().getSimpleName()) || find) {
				find = true;
				beginIndex = i;
				assembledTimes[i - beginIndex] = stateTimeMapper[i];
			}
		}
		for (int j = 0; j < beginIndex; j++) {
			assembledTimes[stateTimeMapper.length - beginIndex + j] = stateTimeMapper[j];
		}
		new Thread(new StateChangeThread(this, assembledTimes)).start();
	}

	public static void getInstance(String address, State beginState, Map<State, Integer>[] stateTimeMapper,
			Map<String, State> walkmanPassingState, Map<String, TrafficLights> singleEntityMapper) {
		synchronized (TrafficLights.class) {
			if (singleEntityMapper.get(address) == null) {
				TrafficLights trafficLights = new TrafficLights(address, beginState, stateTimeMapper,
						walkmanPassingState);
				singleEntityMapper.put(address, trafficLights);
			}
		}
	}

	public void addWalkman(Walkman walkman) {
		if (!walkmanPassing) {
			if (!walkmanQueue.contains(walkman)) {
				walkmanQueue.add(walkman);
				walkman.waitNotice(walkManGo().getMessage());
			}
		} else if (!walkmanPassingAdd.contains(walkman) && !walkmanQueue.contains(walkman)) {
			walkmanPassingAdd.add(walkman);
			walkman.passLinkNotice();
		}
	}

	public void addVehicle(Vehicle vehicle) {
		TrafficMessage trafficMessage = vehicleGo();
		if (walkmanPassing) {
			if (!vehicleQueue.contains(vehicle)) {
				vehicleQueue.add(vehicle);
				vehicle.waitNotice(trafficMessage.getMessage());
			}
		} else if (!vehiclePassingAdd.contains(vehicle) && !vehicleQueue.contains(vehicle)) {
			vehiclePassingAdd.add(vehicle);
			vehicle.passLinkNotice();
		}
	}

	public void deleteWalkman(Walkman walkman) throws Exception {
		// TODO Auto-generated method stub
		if (walkmanPassing == true) {
			if (!walkmanQueue.contains(walkman)) {
				throw new Exception("你已通过道路或你还没到红路灯处!");
			} else {
				if (walkmanPassingDelete == null) {
					walkmanPassingDelete = new ConcurrentHashMap<>();
				}
				walkmanPassingDelete.put(walkman, 1);
			}
		} else {
			if (walkmanQueue == null) {
				throw new Exception("行人等待队列中没有人，无法执行删除操作!");
			} else if (walkmanQueue.contains(walkman)) {
				walkmanQueue.remove(walkman);
			}
		}
	}

	public boolean isWalkmanPassing() {
		return walkmanPassing;
	}

	public void setWalkmanPassing(boolean walkmanPassing) {
		this.walkmanPassing = walkmanPassing;
	}

	public Map<String, State> getWalkmanPassingState() {
		return walkmanPassingState;
	}

	public void setWalkmanPassingState(Map<String, State> walkmanPassingState) {
		this.walkmanPassingState = walkmanPassingState;
	}

	public Map<Walkman, Integer> getWalkmanPassingDelete() {
		return walkmanPassingDelete;
	}

	public boolean isVehiclePassing() {
		return vehiclePassing;
	}

	public void setVehiclePassing(boolean vehiclePassing) {
		this.vehiclePassing = vehiclePassing;
	}

	public ConcurrentLinkedQueue<Walkman> getWalkmanQueue() {
		return walkmanQueue;
	}

	public void setWalkmanQueue(ConcurrentLinkedQueue<Walkman> walkmanQueue) {
		this.walkmanQueue = walkmanQueue;
	}

	public ConcurrentLinkedQueue<Vehicle> getVehicleQueue() {
		return vehicleQueue;
	}

	public void setVehicleQueue(ConcurrentLinkedQueue<Vehicle> vehicleQueue) {
		this.vehicleQueue = vehicleQueue;
	}

	public ConcurrentLinkedQueue<Vehicle> getVehiclePassingAdd() {
		return vehiclePassingAdd;
	}

	public void setVehiclePassingAdd(ConcurrentLinkedQueue<Vehicle> vehiclePassingAdd) {
		this.vehiclePassingAdd = vehiclePassingAdd;
	}

	public void setWalkmanPassingDelete(ConcurrentHashMap<Walkman, Integer> walkmanPassingDelete) {
		this.walkmanPassingDelete = walkmanPassingDelete;
	}

	public ConcurrentLinkedQueue<Walkman> getWalkmanPassingAdd() {
		return walkmanPassingAdd;
	}

	public void setWalkmanPassingAdd(ConcurrentLinkedQueue<Walkman> walkmanPassingAdd) {
		this.walkmanPassingAdd = walkmanPassingAdd;
	}
}
